;
;  Program:  PWD
;  Version:  1.1
;  Author:  Richard Conn
;  Date:  6 Jan 83
;  Previous Versions:  1.0 (7 Dec 82)
;  Derivation:  PWD.MAC was derived in concept from CD.MAC, Version 2.1
;
vers	equ	11

;
;	This program is Copyright (c) 1982, 1983 by Richard Conn
;	All Rights Reserved
;
;	ZCPR2 and its utilities, including this one, are released
; to the public domain.  Anyone who wishes to USE them may do so with
; no strings attached.  The author assumes no responsibility or
; liability for the use of ZCPR2 and its utilities.
;
;	The author, Richard Conn, has sole rights to this program.
; ZCPR2 and its utilities may not be sold without the express,
; written permission of the author.
;


;
;	PWD is designed to allow the user to print his working directory
; (PWD=Print Working Directory) and to find out what directories
; are available to him to move to.
; 	Intended to be small in size, PWD accepts a command of the
; following forms:
;
;		PWD			<-- Print Current Info
;		PWD DIR			<-- Print Directory Info
;		PWD //			<-- Print Help Message
;

;
;  CP/M Constants
;
cpm	equ	0	; Warm Boot Address
entry	equ	cpm+5	; BDOS Entry Point
fcb	equ	5ch	; Location of Default FCB
tbuff	equ	80h	; Temporary Input Line Buffer
cr	equ	0dh
lf	equ	0ah

;
;  Externals
;
	ext	cline	; save current line as string
	ext	zgpins	; init ZCPR2 buffers
	ext	zdnfind	; used to determine directory user/disk
	ext	retud	; return current user/disk
	ext	print	; print routine
	ext	zdname	; load directory names
	ext	cout	; char output
	ext	codend	; end of code
	ext	padc	; print A as decimal
	ext	madc	; print A in memory
	ext	crlf	; new line
	ext	cin	; char input

;
;  Branch to Start of Program
;
	jmp	start

;
;******************************************************************
;
;  SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
;	This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;

;
;  EXTERNAL PATH DATA
;
EPAVAIL:
	DB	0FFH	; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
	DW	40H	; ADDRESS OF EXTERNAL PATH IF AVAILABLE

;
;  INTERNAL PATH DATA
;
INTPATH:
	DB	0,0	; DISK, USER FOR FIRST PATH ELEMENT
			; DISK = 1 FOR A, '$' FOR CURRENT
			; USER = NUMBER, '$' FOR CURRENT
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0	; DISK, USER FOR 8TH PATH ELEMENT
	DB	0	; END OF PATH

;
;  MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
	DB	0FFH	; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
	DW	0FF00H	; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE

;
;  DISK/USER LIMITS
;
MDISK:
	DB	4	; MAXIMUM NUMBER OF DISKS
MUSER:
	DB	31	; MAXIMUM USER NUMBER

;
;  FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
	DB	0FFH	; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
	DB	0FFH	; ALLOW USER CHANGE? (0=NO, 0FFH=YES)

;
;  PRIVILEGED USER DATA
;
PUSER:
	DB	10	; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
	DB	'chdir',0	; PASSWORD FOR MOVING INTO PRIV USER AREAS
	DS	41-($-PPASS)	; 40 CHARS MAX IN BUFFER + 1 for ending NULL

;
;  CURRENT USER/DISK INDICATOR
;
CINDIC:
	DB	'$'	; USUAL VALUE (FOR PATH EXPRESSIONS)

;
;  DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
	DW	80H	; TBUFF AREA

;
;  NAMED DIRECTORY INFORMATION
;
NDRADR:
	DW	00000H	; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
	DB	64	; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
	DB	'NAMES   '	; NAME OF DISK NAME FILE
	DB	'DIR'		; TYPE OF DISK NAME FILE

;
;  REQUIREMENTS FLAGS
;
EPREQD:
	DB	0FFH	; EXTERNAL PATH?
MCREQD:
	DB	0FFH	; MULTIPLE COMMAND LINE?
MXREQD:
	DB	0FFH	; MAX USER/DISK?
UDREQD:
	DB	0FFH	; ALLOW USER/DISK CHANGE?
PUREQD:
	DB	0FFH	; PRIVILEGED USER?
CDREQD:
	DB	0FFH	; CURRENT INDIC AND DMA?
NDREQD:
	DB	0FFH	; NAMED DIRECTORIES?
Z2CLASS:
	DB	0	; CLASS 0
	DB	'ZCPR2'
	DS	10	; RESERVED

;
;  END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;

;
;  Start of Program
;
start:
	call	zgpins	; install ZCPR2 variables

	call	print	; print banner
	db	'PWD, Version '
	db	vers/10+'0','.',(vers mod 10)+'0',0

	lxi	h,0	; set no loaded directory file
	shld	ndfadr
	xra	a	; set zero count
	sta	ndfcnt
	lxi	h,tbuff	; pt to input line
	call	cline	; save and buffer input line

;
;  Skip to first non-blank and process if Help requested
;
sblank:
	mov	a,m	; pt to char
	inx	h	; pt to next
	cpi	' '	; <sp>?
	jz	sblank
	dcx	h	; pt to first non-blank
	ora	a	; print directory info?
	jz	cwd
	cpi	'D'	; dir option?
	jz	pwd

;
;  Print Help Message
;
	call	print
	db	cr,lf,'	PWD is a ZCPR2 named directory display utility'
	db	cr,lf,'(PWD=Print Working Directory).  Command Forms are:'
	db	cr,lf,'		PWD	<-- Print Current Info'
	db	cr,lf,'		PWD DIR	<-- Print Available Directories'
	db	cr,lf,'		PWD //	<-- Print Help Message'
	db	cr,lf,0
	ret

;
;  Print Directories and Current Working Directory
;
pwd:
	call	retud	; get current disk/user
	mov	a,b	; save current disk
	sta	cdisk
	mov	a,c	; save current user
	sta	cuser
	call	print
	db	cr,lf,cr,lf,'** Directory Display **',cr,lf,0
	lhld	ndradr	; check for named directory buffer
	mov	a,l
	ora	h	; HL=0 if none
	jnz	pwdn
	call	print
	db	'** No Named Directory Buffer **',0
	jmp	pwd0
;
;  Print contents of named directory buffer
;
pwdn:
	inx	h	; pt to entry count
	mov	c,m	; get count in C
	mov	a,c	; check for any entries
	ora	a
	jz	pwd0
	inx	h	; pt to first entry
	call	print
	db	cr,lf,'	** Named Directory Memory-Based Definitions **',0
	call	prndir	; print named directory
	call	print
	db	cr,lf,cr,lf,'Strike Any Key to Continue - ',0
	call	cin
	call	crlf
pwd0:
	call	codend	; get end of code
	call	zdname	; load names.dir entries
	jnz	pwd1
	call	print
	db	cr,lf,'** No Directory Names File **',0
	jmp	pwd2
pwd1:
	mov	a,c	; save count in buffer
	sta	ndfcnt
	shld	ndfadr	; save address in buffer
	call	print
	db	cr,lf,'	** Named Directory  Disk-Based  Definitions **',0
	call	prndir	; print named directory
pwd2:
	call	print
	db	cr,lf,cr,lf,'** Current Directory **',0
	lhld	ndradr	; check named directory buffer
	mov	a,h	; any buffer?
	ora	l
	jz	pwd3
	inx	h	; pt to count
	mov	c,m	; get count in C
	inx	h	; pt to first entry
	call	prcwd	; print current working dir
	rnz		; found
pwd3:
	lhld	ndfadr	; get address of NAMES.DIR file in memory
	lda	ndfcnt	; get entry count
	mov	c,a	; ... in C
	call	prcwd
	rnz		; found
	call	print
	db	cr,lf,'	Noname',0
	ret
;
;  Print Current Working Directory alone
;
cwd:
	call	retud	; get current disk/user
	mov	a,b	; save current disk
	sta	cdisk
	mov	a,c	; save current user
	sta	cuser
	call	codend	; get end of code
	call	zdname	; load names.dir entries
	jz	pwd2
	mov	a,c	; save count in buffer
	sta	ndfcnt
	shld	ndfadr	; save address in buffer
	jmp	pwd2

;
;  Print named directory pointed to by HL whose entry count is in C
;
prndir:
	call	crlf	; new line
	mov	a,c	; print total count
	call	padc
	call	print
	db	' Directory Entries Total ',0
	ora	a	; any entries?
	rz
	call	prpriv	; print privileged count
	mvi	b,0	; set new line count
	mvi	d,0ffh	; set last dir to empty
	push	h	; save ptr to first entry
	push	b	; save entry count
prnd1:
	call	dsel	; check for priv rights to see this entry
	jz	prnd2	; do not see
	call	diskck	; check for new disk
	mov	a,b	; get flag
	ani	3	; mask
	cz	crlf	; new line
	inr	b	; increment flag
	call	pentry	; print entry
	dcr	c	; count down
	jnz	prnd1
	pop	b	; get entry count
	pop	h	; get ptr to first entry
	ret
prnd2:
	call	add10	; pt to next entry (HL=HL+10)
	dcr	c	; count down
	jnz	prnd1
	pop	b	; get entry count
	pop	h	; get ptr to first entry
	ret
;
;  Print Count of Privileged Directories
;
prpriv:
	mvi	a,'('	; print text
	call	cout
	push	h	; save HL
	push	b	; save BC
	mvi	b,0	; set count
prp1:
	call	dsel	; priv dir?
	jnz	prp2
	inr	b	; increment count
prp2:
	call	add10	; HL=HL+10
	dcr	c	; count down
	jnz	prp1
	mov	a,b	; get count
	pop	b	; restore regs
	pop	h
	call	padc	; print decimal value
	call	print
	db	' Directories Hidden) --',0
	ret

;
;  Print Current Directory
;
prcwd:
	mov	a,c	; check for no entries
	ora	a
	rz
	lda	cuser	; get current user
	mov	e,a	; ... in E
	lda	cdisk	; get current disk
	mov	b,a	; ... in B
prcwd1:
	mov	a,m	; get disk
	cmp	b	; compare disks
	jnz	prcwd2
	inx	h	; pt to user
	mov	a,m	; get user
	dcx	h	; pt back
	cmp	e	; compare users
	jnz	prcwd2
	call	print
	db	cr,lf,'	',0
	mov	a,m	; get disk number
	adi	'A'	; convert to letter
	call	cout
	call	pe0	; print entry without leading spaces
	mvi	a,0ffh	; set OK flag
	ora	a
	ret
prcwd2:
	call	add10	; HL=HL+10 to pt to next entry
	dcr	c	; count down
	jnz	prcwd1
	xra	a	; set not found flag
	ret

;
;  Determine if user is priveleged, and, if not, then select only those
;  directory entries he has access to without a password.  On return,
;  Zero Flag Set (Z) if user should not see the entry pted to by HL
;
dsel:
	push	b	; save BC
	lda	cuser	; get current user
	mov	c,a	; ... in C
	lda	puser	; start of priveleged user areas
	cmp	c	; compare current and priv users
	jz	dselok	; OK if same
	jc	dselok	; OK if current > priv
	inx	h	; pt to user number
	mov	c,m	; get user number
	dcx	h	; pt to disk number
	cmp	c	; compare entry and priv users
	jz	dselno	; no select if entry is priv
	jnc	dselok	; select is entry is not priv
dselno:
	pop	b	; restore BC
	xra	a	; return not OK
	ret
dselok:
	pop	b	; restore BC
	mvi	a,0ffh	; return OK
	ora	a
	ret
;
;  Check to see if new disk, and, if so, print banner and set current disk
;
diskck:
	mov	a,m	; get next disk number
	cmp	d	; same as before?
	rz
	mov	d,a	; set new disk number
	mvi	b,0	; reset entry/line flag
	call	crlf	; new line
	adi	'A'	; convert to letter
	call	cout
	call	print
	db	' --',0
	ret
;
;  HL=HL+10 to pt to next entry
;
add10:
	mov	a,l	; add low
	adi	10
	mov	l,a
	mov	a,h	; add high
	aci	0
	mov	h,a
	ret
;
;  Print entry pted to by HL; on return, HL pts to next entry
;
pentry:
	mvi	a,' '	; print leading spaces
	call	cout
	call	cout
pe0:
	push	d	; save DE
	inx	h	; skip disk number
	mov	a,m	; get user number
	call	pusr	; print user number
	inx	h	; pt to next char
	mvi	d,8	; 8 chars
pe1:
	mov	a,m	; get char
	call	cout	; print it
	inx	h	; pt to next
	dcr	d	; count down
	jnz	pe1
	pop	d	; restore de
	ret
;
;  Print user number in A as 2 decimal digits with leading spaces
;
pusr:
	push	d	; save DE
	lxi	d,buff	; pt to buffer
	push	d	; save ptr
	call	madc	; load number into buffer as ASCII chars
	pop	d	; get ptr
	inx	d	; pt to 2nd letter (1st digit)
	ldax	d	; get 1st digit
	call	cout
	inx	d	; pt to 2nd digit
	ldax	d	; get it
	call	cout
	mvi	a,':'	; separator
	call	cout
	mvi	a,' '	; print space
	call	cout
	pop	d	; restore DE
	ret
;
;  Buffers
;
buff:
	ds	3	; number storage buffer
cuser:
	ds	1	; current user
cdisk:
	ds	1	; current disk
ndfcnt:
	ds	1	; named directory file entry count
ndfadr:
	ds	2	; named directory file load address

	end
